package main

import (
    "fmt"
    "reflect"
)

const (
    TextBlack = iota + 30
    TextRed
    TextGreen
    TextYellow
    TextBlue
    TextMagenta
    TextCyan
    TextWhite
)

//将说明打印成蓝色
func debug(s string) {
    fmt.Printf("\x1b[0;%dm%s\x1b[0m\n", TextBlue, s)
}
/*
interface是一套method的组合, 一个约定,
约定:”所有不同的结构体，大家都使用这一套函数名称，来命名(相同功能的) 方法(函数)，并各自定义自己的方法实现“
type InterfaceName interface {
    方法名1( 参数列表1 ) 返回值列表1
    方法名2( 参数列表2 ) 返回值列表2
}

例如，长方形和圆是不同结构体，有各自的长宽和半径定义，但是大家都有相同的功能需求：求周长。
这个求周长的函数就可以是interface中的一个method，名称一样，但是实现不一样。
type 长方形 struct {
    长
    宽
}
type 圆 struct {
    半径
}
type 公式 interface {
    面积公式() 返回值列表1
    周长公式() 返回值列表2
}
方法定义示例：
func (a 长方形) 周长公式() {return 2(a.长+a.宽)}
func (a 圆) 周长公式() {return 2*圆周率*a.半径}

----------------------------------------------------------------
代码中，实际使用时，需要结构体Struct和interface组合
1，struct只负责定义数据格式，
   interface定义method名称
2, 用func (struct )method(){}定义该结构类型对应的method的具体实现
3， 不同struct的method名称一样，但是实现可以不一样
   例：有结构struct1, struct2, 有interface类型 itf = {method1, method2}
   定义见下面代码。
   结果可以理解为类似于C语言的带函数指针的结构体，如struct1 { a, b, method1(), method2()}
   调用时，直接struct1.method1(), 区别是，这里struct1类似于输入参数，可以在method中读取Struct1的值
   C语言则需要将结构体做为参数传入。

type itf interface {
    method1(a,b)Type
    method2(a,b)Type
    ...
}
type struct1 struct {
    a int
    b string
}
type struct2 struct {
    c int
    d string
}

//看情况设置s,可以是结构体，也可以是结构体指针，和参数性质相同，是一个拷贝
func (s struct1) method1(a,b) (Type) {

}
func (s struct1) method2(a,b) (Type) {

}
func (s struct2) method1(a,b) (Type) {

}
func (s struct2) method2(a,b) (Type) {

}
*/

type handle interface {
    Increase()int
    PrintNum()
    printNum()
}
type numberInt struct {
    n int
}
type numberFloat struct {
    n numberInt
    m float64
}
func (x *numberInt) Increase() int {
    x.n += 1
    return 0
}
func (x *numberFloat) Increase() int {
    x.n.Increase()
    x.m += 0.1
    return 0
}

func (x *numberInt) printNum() {
    x.PrintNum()
    fmt.Print("\n")
}
func (x *numberFloat) printNum() {
    x.PrintNum()
    fmt.Print("\n")
}
func (x *numberFloat) PrintNum() {
    x.n.PrintNum()
    fmt.Print(".", x.m*10000)
}

func (x *numberInt) PrintNum() {
    fmt.Printf("%d", x.n)
}

//返回值可以是 handle, 也可以是具体的类型, 返回值如果为handle,则表示是一个interface
//如果createNumberInt要做为另一个interface中的某个method,
//而这个method为了统一格式，应对多种数据结构类型，可以将返回值定义为一个interface
//interface不负责表示具体结构体类型，所以返回值可以通配所有的结构体类型，只要该类型定义了interface中的一整套method
//func createNumberInt()(*numberInt) {
func createNumberInt()(h handle) {
    num := &numberInt{0}
    return num
}

func createNumberFloat()(h handle) {
    num := &numberFloat{numberInt{0}, 0}
    return num
}

func interfacePrint(itf interface{}) {
    fmt.Printf("Type %T, %#v\n", itf, itf)
    //fmt.Println(itf)
}

func returnInterface(num int) interface{} {
    if num == 0 {
        return "num == 0"
    } else {
        return 1
    }
}

func main() {
    debug("1, empty interface")
    var a interface{}
    interfacePrint(a)

    debug("1.1, empty interface 赋值int后")
    a = 22
    interfacePrint(a)

    debug("1.2, empty interface 赋值int后，与其它数字进行运算")
    //a += 33 //编译不通过
    //a.(int) = a.(int) + 33//编译不过
    a = a.(int) + 33
    interfacePrint(a)

    debug("1.3, empty interface 二次赋值为String，覆盖")
    a = "hello world"
    interfacePrint(a)

    debug("1.4, empty interface 赋值String后，与其它字符串拼接")
    buf := "hi"
    //a = a + buf//编译不通过
    a = a.(string) + buf
    interfacePrint(a)

    debug("1.5, empty interface 赋值map后，进行遍历map操作")
    a = map[string]int{
        "alice":    31,
        "charltie": 34,
        "vilen":    22, // 必须有逗号
    }
    interfacePrint(a)
    //for _, age := range a {//编译不过
    for _, age := range a.(map[string]int) {
        fmt.Printf("%d\n", age)
    }

    debug("1.6, empty interface 赋值slice后，进行slice操作")
    a = []int{1, 2, 3, 4, 5, 9:100, 7:9}
    interfacePrint(a)
    a = append(a.([]int), 91)
    interfacePrint(a)

    debug("1.7, empty interface 断言, 判断interface中的值的类型是否为[]int")
    _,ok := a.([]int)
    if ok {
        fmt.Println(a)
    }

    debug("1.8, empty interface 做为map的值")
    m := make(map[string]interface{})
    m["name"] = "vilen"
    m["age"] = 24
    interfacePrint(m)
    //m["age"] = m["age"] + 24//编译不通过
    m["age"] = m["age"].(int) + 24
    interfacePrint(m)

    debug("1.9, empty interface 做为slice的值")
    var s = make([]interface{},6)
    s[3] = "vilen"
    s[4] = 33
    interfacePrint(s)

    debug("1.10, empty interface 做为函数返回值, 可以在函数中自由返回不同的类型")
    interfacePrint(returnInterface(3))
    interfacePrint(returnInterface(0))

    debug("1.11, 类型转换为empty interface")
    b := int(100)
    befce := interface{}(b)
    interfacePrint(befce)

    debug("1.12, empty interface赋值指针")
    var eface interface{}
    var intp *int
    fmt.Println("eface type=",reflect.TypeOf(eface))
    interfacePrint(eface)
    fmt.Println("intp =", intp, intp == nil)
    eface = intp
    interfacePrint(eface)
    fmt.Println("eface=", eface, eface == nil, "interface必须是类型和数据都是nil, 才是==nil")


    debug("2, 非empty interface的使用, 返回值为interface,查看实际的类型")
    numInt := createNumberInt()
    interfacePrint(numInt)
    for i := 0; i < 10; i++ {
        numInt.Increase()
        numInt.printNum()
    }
    var iface wdget
    fmt.Println("iface type=", reflect.TypeOf(iface))
    debug("2.1, 非empty interface的使用, 返回值为interface,查看实际的类型")
    numFloat := createNumberFloat()
    interfacePrint(numFloat)
    //fmt.Println(reflect.TypeOf(numFloat))
    for i := 0; i < 10; i++ {
        numFloat.Increase()
        numFloat.printNum()
    }

    methodS := []wdget{T1{2}, T2{1}}
    fmt.Println(methodS)
    var t1 = T1{1}
    var t2 = T1{2}
    aa := []wdget{}
    aa = append(aa, t1, t2)
    fmt.Println(aa)

    debug("3， interface作为参数")
    var x interface{} = x1{}
    fmt.Println(print(x))

    debug("4, map[string]interface")
    var resJsonContent map[string]interface{}
    resJsonContent["abc"]="ttt"
    fmt.Println(resJsonContent)

}

type x1 struct {
    a int
    b int
}

func print(unknow  interface{}) string{
    switch unknow.(type) {
    case string:
        return "x1"
    case int:
        return "int"
    case x1 :
        return "x1"
    }

    return ""
}

func handleh(h handle) {

}


type wdget interface {
    create() int
}
type T1 struct {
    n int
}
func (x T1) create() int {
    return 1
}
type T2 struct {
    n int
}
func (x T2) create() int {
    return 2
}
func IsNil(i interface{}) bool {
    vi := reflect.ValueOf(i)
    if vi.Kind() == reflect.Ptr {
        return vi.IsNil()
    }
    return false
}

func IsNil2(i interface{}) bool {
    defer func() {
        recover()
    }()
    vi := reflect.ValueOf(i)
    return vi.IsNil()
}